home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / FTPCLI.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  19KB  |  783 lines

  1. /* FTP client (interactive user) code */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "mbuf.h"
  5. #include "session.h"
  6. #include "cmdparse.h"
  7. #include "timer.h"
  8. #include "proc.h"
  9. #include "tty.h"
  10. #include "socket.h"
  11. #include "ftp.h"
  12. #include "ftpcli.h"
  13. #include "commands.h"
  14. #include "netuser.h"
  15.  
  16. static int doascii __ARGS((int argc,char *argv[],void *p));
  17. static int dobinary __ARGS((int argc,char *argv[],void *p));
  18. static int doftpcd __ARGS((int argc,char *argv[],void *p));
  19. static int doget __ARGS((int argc,char *argv[],void *p));
  20. static int dolist __ARGS((int argc,char *argv[],void *p));
  21. static int dols __ARGS((int argc,char *argv[],void *p));
  22. static int domkdir __ARGS((int argc,char *argv[],void *p));
  23. static int donothing __ARGS((int argc,char *argv[],void *p));
  24. static int doput __ARGS((int argc,char *argv[],void *p));
  25. static int doquit __ARGS((int argc,char *argv[],void *p));
  26. static int dormdir __ARGS((int argc,char *argv[],void *p));
  27. static int dotype __ARGS((int argc,char *argv[],void *p));
  28. static struct mbuf *getline __ARGS((struct session *sp,char *prompt));
  29. static int getresp __ARGS((int s,int mincode));
  30. static int getsub __ARGS((struct ftpcli *ftp,char *command,char *remotename,
  31.     char *localname));
  32. static void sendport __ARGS((int s,struct sockaddr_in *socket));
  33.  
  34. extern char Nospace[],Badhost[];
  35. static char Notsess[] = "Not an FTP session!\n";
  36.  
  37. static struct cmds Ftpcmds[] = {
  38.     "",        donothing,    0, 0, NULLCHAR,
  39.     "ascii",    doascii,    0, 0, NULLCHAR,
  40.     "binary",    dobinary,    0, 0, NULLCHAR,
  41.     "cd",        doftpcd,    0, 2, "cd <directory>",
  42.     "dir",        dolist,        0, 0, NULLCHAR,
  43.     "list",        dolist,        0, 0, NULLCHAR,
  44.     "get",        doget,        0, 2, "get remotefile <localfile>",
  45.     "ls",        dols,        0, 0, NULLCHAR,
  46.     "mkdir",    domkdir,    0, 2, "mkdir <directory>",
  47.     "nlst",        dols,        0, 0, NULLCHAR,
  48.     "quit",        doquit,        0, 0, NULLCHAR,
  49.     "rmdir",    dormdir,    0, 2, "rmdir <directory>",
  50.     "put",        doput,        0, 2, "put localfile <remotefile>",
  51.     "type",        dotype,        0, 0, NULLCHAR,
  52.     NULLCHAR,    NULLFP,        0, 0, NULLCHAR,
  53. };
  54.  
  55. /* Handle top-level FTP command */
  56. int
  57. doftp(argc,argv,p)
  58. int argc;
  59. char *argv[];
  60. void *p;
  61. {
  62.     struct session *sp;
  63.     struct ftpcli ftp;
  64.     struct sockaddr_in fsocket;
  65.     int resp;
  66.     struct mbuf *bp,*bpsav;
  67.     char *cp;
  68.     int control;
  69.  
  70.     /* Allocate a session control block */
  71.     if((sp = newsession(argv[1],FTP)) == NULLSESSION){
  72.         printf("Too many sessions\n");
  73.         freeargs(argc,argv);
  74.         return 1;
  75.     }
  76.     memset((char *)&ftp,0,sizeof(ftp));
  77.     ftp.control = ftp.data = -1;
  78.  
  79.     sp->cb.ftp = &ftp;    /* Downward link */
  80.     ftp.session = sp;    /* Upward link */
  81.     ftp.output = Curproc;
  82.  
  83.     fsocket.sin_family = AF_INET;
  84.     if(argc < 3)
  85.         fsocket.sin_port = IPPORT_FTP;
  86.     else
  87.         fsocket.sin_port = atoi(argv[2]);
  88.  
  89.     freeargs(argc,argv);
  90.     Current = sp;
  91.     Mode = CONV_MODE;
  92.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  93.         printf(Badhost,sp->name);
  94.         freesession(sp);
  95.         return 1;
  96.     }
  97.     /* Open the control connection */
  98.     if((control = sp->s = ftp.control = socket(AF_INET,SOCK_STREAM,0)) == -1){
  99.         printf("Can't create socket\n");
  100.         freesession(sp);
  101.         return 1;
  102.     }
  103.     printf("Trying %s...\n",psocket((struct sockaddr *)&fsocket));
  104.     if(connect(control,(char *)&fsocket,sizeof(fsocket)) == -1)
  105.         goto quit;
  106.     printf("FTP session %u connected to %s\n",(unsigned)(sp-Sessions),
  107.         sp->name);
  108.  
  109.     /* Wait for greeting from server */
  110.     resp = getresp(control,200);
  111.  
  112.     /* Now process responses and commands */
  113.     for(;;){
  114.         switch(resp){
  115.         case -1:
  116.             goto quit;
  117.         case 220: /* Sign-on banner; prompt for and send USER command */
  118.             bp = qdata("USER ",5);
  119.             append(&bp,getline(sp,"Enter user name: "));
  120.             if(send_mbuf(control,bp,0,NULLCHAR,0) == -1)
  121.                 goto quit;
  122.             resp = getresp(control,200);
  123.             break;
  124.         case 331: /* Password prompt; get password */
  125.             ttysetmode(TTY_EDIT);    /* turn off echo */
  126.             bp = getline(sp,"Password: ");
  127.             printf("\r\n");
  128.             ttysetmode(TTY_EDIT|TTY_ECHO);
  129.             if(len_mbuf(bp) != 0 && bp->data[0] != '\r'){
  130.                 bp = pushdown(bp,5);
  131.                 strcpy(bp->data,"PASS ");
  132.                 if(send_mbuf(control,bp,0,NULLCHAR,0) == -1)
  133.                     goto quit;
  134.                 resp = getresp(control,200);
  135.                 break;
  136.             } else
  137.                 free_p(bp); /* Null response, don't send */
  138.  
  139.         default:    /* Note fall-thru */
  140.             /* Test the control channel first */
  141.             if(sockstate(control) == NULLCHAR)
  142.                 goto quit;
  143.  
  144.             bp = getline(sp,"ftp> ");
  145.  
  146.             /* Copy because cmdparse modifies the original */
  147.             bpsav = copy_p(bp,len_mbuf(bp));
  148.             if((resp = cmdparse(Ftpcmds,bp->data,sp)) != -1){
  149.                 /* Valid command, free buffer and get another */
  150.                 free_p(bpsav);
  151.             } else {
  152.                 /* Not a local cmd, send to remote server */
  153.                 if(send_mbuf(control,bpsav,0,NULLCHAR,0) == -1){
  154.                     free_p(bp);
  155.                     goto quit;
  156.                 }
  157.                 resp = getresp(control,200);
  158.             }
  159.             free_p(bp);
  160.             break;
  161.         }
  162.     }
  163. quit:    cp = sockerr(control);
  164.     printf("FTP session %u closed: %s\n",(unsigned)(sp - Sessions),
  165.      cp != NULLCHAR ? cp : "EOF");
  166.  
  167.     if(ftp.fp != NULLFILE && ftp.fp != stdout)
  168.         fclose(ftp.fp);
  169.     if(ftp.data != -1)
  170.         close_s(ftp.data);
  171.     if(ftp.control != -1)
  172.         close_s(ftp.control);
  173.     if(ftp.session != NULLSESSION)
  174.         freesession(ftp.session);
  175.     return 0;
  176. }
  177.  
  178. /* Handle null line to avoid trapping on first command in table */
  179. static int
  180. donothing(argc,argv,p)
  181. int argc;
  182. char *argv[];
  183. void *p;
  184. {
  185.     return 0;
  186. }
  187. /* Close session */
  188. static int
  189. doquit(argc,argv,p)
  190. int argc;
  191. char *argv[];
  192. void *p;
  193. {
  194.     register struct ftpcli *ftp;
  195.     int control;
  196.     struct session *sp;
  197.  
  198.     sp = (struct session *)p;
  199.     if(sp == NULLSESSION)
  200.         return -1;
  201.     ftp = sp->cb.ftp;
  202.     control = ftp->control;
  203.     usprintf(control,"QUIT\r\n");
  204.     getresp(control,200);    /* Get the closing message */
  205.     getresp(control,200);    /* Wait for the server to close */
  206.     return -1;
  207. }
  208.  
  209. /* Translate 'cd' to 'cwd' for convenience */
  210. static int
  211. doftpcd(argc,argv,p)
  212. int argc;
  213. char *argv[];
  214. void *p;
  215. {
  216.     register struct ftpcli *ftp;
  217.     struct session *sp;
  218.  
  219.     sp = (struct session *)p;
  220.     if(sp == NULLSESSION)
  221.         return -1;
  222.     ftp = sp->cb.ftp;
  223.     usprintf(ftp->control,"CWD %s\r\n",argv[1]);
  224.     return getresp(ftp->control,200);
  225. }
  226. /* Translate 'mkdir' to 'xmkd' for convenience */
  227. static int
  228. domkdir(argc,argv,p)
  229. int argc;
  230. char *argv[];
  231. void *p;
  232. {
  233.     register struct ftpcli *ftp;
  234.     struct session *sp;
  235.  
  236.     sp = (struct session *)p;
  237.     if(sp == NULLSESSION)
  238.         return -1;
  239.     ftp = sp->cb.ftp;
  240.     usprintf(ftp->control,"XMKD %s\r\n",argv[1]);
  241.     return getresp(ftp->control,200);
  242. }
  243. /* Translate 'rmdir' to 'xrmd' for convenience */
  244. static int
  245. dormdir(argc,argv,p)
  246. int argc;
  247. char *argv[];
  248. void *p;
  249. {
  250.     register struct ftpcli *ftp;
  251.     struct session *sp;
  252.  
  253.     sp = (struct session *)p;
  254.     if(sp == NULLSESSION)
  255.         return -1;
  256.     ftp = sp->cb.ftp;
  257.     usprintf(ftp->control,"XRMD %s\r\n",argv[1]);
  258.     return getresp(ftp->control,200);
  259. }
  260. static int
  261. dobinary(argc,argv,p)
  262. int argc;
  263. char *argv[];
  264. void *p;
  265. {
  266.     char *args[2];
  267.  
  268.     args[1] = "I";
  269.     return dotype(2,args,p);
  270. }
  271. static int
  272. doascii(argc,argv,p)
  273. int argc;
  274. char *argv[];
  275. void *p;
  276. {
  277.     char *args[2];
  278.  
  279.     args[1] = "A";
  280.     return dotype(2,args,p);
  281. }
  282.  
  283. /* Handle "type" command from user */
  284. static int
  285. dotype(argc,argv,p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289. {
  290.     register struct ftpcli *ftp;
  291.     int control;
  292.     struct session *sp;
  293.  
  294.     sp = (struct session *)p;
  295.     if(sp == NULLSESSION)
  296.         return -1;
  297.     ftp = sp->cb.ftp;
  298.     control = ftp->control;
  299.     if(argc < 2){
  300.         switch(ftp->type){
  301.         case IMAGE_TYPE:
  302.             printf("Image\n");
  303.             break;
  304.         case ASCII_TYPE:
  305.             printf("Ascii\n");
  306.             break;
  307.         case LOGICAL_TYPE:
  308.             printf("Logical bytesize %u\n",ftp->logbsize);
  309.             break;
  310.         }
  311.         return 0;
  312.     }
  313.     switch(*argv[1]){
  314.     case 'i':
  315.     case 'I':
  316.     case 'b':
  317.     case 'B':
  318.         ftp->typesent = ftp->type = IMAGE_TYPE;
  319.         usprintf(control,"TYPE I\r\n");
  320.         break;
  321.     case 'a':
  322.     case 'A':
  323.         ftp->typesent = ftp->type = ASCII_TYPE;
  324.         usprintf(control,"TYPE A\r\n");
  325.         break;
  326.     case 'L':
  327.     case 'l':
  328.         ftp->typesent = ftp->type = LOGICAL_TYPE;
  329.         ftp->logbsize = atoi(argv[2]);
  330.         usprintf(control,"TYPE L %s\r\n",argv[2]);
  331.         break;
  332.     default:
  333.         printf("Invalid type %s\n",argv[1]);
  334.         return 1;
  335.     }
  336.     return getresp(control,200);
  337. }
  338. /* Start receive transfer. Syntax: get <remote name> [<local name>] */
  339. static int
  340. doget(argc,argv,p)
  341. int argc;
  342. char *argv[];
  343. void *p;
  344. {
  345.     char *remotename,*localname;
  346.     register struct ftpcli *ftp;
  347.     struct session *sp;
  348.  
  349.     sp = (struct session *)p;
  350.     if(sp == NULLSESSION)
  351.         return -1;
  352.     ftp = sp->cb.ftp;
  353.     if(ftp == NULLFTP){
  354.         printf(Notsess);
  355.         return 1;
  356.     }
  357.     remotename = argv[1];
  358.     if(argc < 3)
  359.         localname = remotename;
  360.     else
  361.         localname = argv[2];
  362.  
  363.     return getsub(ftp,"RETR",remotename,localname);
  364. }
  365. /* List remote directory. Syntax: dir <remote files> [<local name>] */
  366. static int
  367. dolist(argc,argv,p)
  368. int argc;
  369. char *argv[];
  370. void *p;
  371. {
  372.     char *remotename,*localname;
  373.     register struct ftpcli *ftp;
  374.     struct session *sp;
  375.  
  376.     sp = (struct session *)p;
  377.     if(sp == NULLSESSION)
  378.         return -1;
  379.     ftp = sp->cb.ftp;
  380.     if(ftp == NULLFTP){
  381.         printf(Notsess);
  382.         return 1;
  383.     }
  384.     remotename = argv[1];
  385.     if(argc > 2)
  386.         localname = argv[2];
  387.     else
  388.         localname = NULLCHAR;
  389.     return getsub(ftp,"LIST",remotename,localname);
  390. }
  391. /* Remote directory list, short form. Syntax: ls <remote files> [<local name>] */
  392. static int
  393. dols(argc,argv,p)
  394. int argc;
  395. char *argv[];
  396. void *p;
  397. {
  398.     char *remotename,*localname;
  399.     register struct ftpcli *ftp;
  400.     struct session *sp;
  401.  
  402.     sp = (struct session *)p;
  403.     if(sp == NULLSESSION)
  404.         return -1;
  405.     ftp = sp->cb.ftp;
  406.     if(ftp == NULLFTP){
  407.         printf(Notsess);
  408.         return 1;
  409.     }
  410.     remotename = argv[1];
  411.     if(argc > 2)
  412.         localname = argv[2];
  413.     else
  414.         localname = NULLCHAR;
  415.     return getsub(ftp,"NLST",remotename,localname);
  416. }
  417. /* Common code to LIST/NLST/RETR */
  418. static int
  419. getsub(ftp,command,remotename,localname)
  420. struct ftpcli *ftp;
  421. char *command,*remotename,*localname;
  422. {
  423.     unsigned long total;
  424.     FILE *fp;
  425.     int cnt,resp,i,control;
  426.     char *mode;
  427.     struct sockaddr_in lsocket;
  428.     int32 startclk,rate;
  429.  
  430.     if(ftp == NULLFTP)
  431.         return -1;
  432.     control = ftp->control;
  433.  
  434.     switch(ftp->type){
  435.     case IMAGE_TYPE:
  436.     case LOGICAL_TYPE:
  437.         mode = WRITE_BINARY;
  438.         break;
  439.     case ASCII_TYPE:
  440.         mode = WRITE_TEXT;
  441.         break;
  442.     }
  443.     /* Send TYPE message, if necessary */
  444.     if(strcmp(command,"LIST") == 0 || strcmp(command,"NLST") == 0){
  445.         if(ftp->typesent != ASCII_TYPE){
  446.             /* Directory listings are always in ASCII */
  447.             usprintf(control,"TYPE A\r\n");
  448.             ftp->typesent = ASCII_TYPE;
  449.             resp = getresp(control,200);
  450.             if(resp == -1 || resp > 299){
  451.                 return 1;
  452.             }
  453.         }
  454.     } else if(ftp->typesent != ftp->type){
  455.         switch(ftp->type){
  456.         case ASCII_TYPE:
  457.             usprintf(control,"TYPE A\r\n");
  458.             break;
  459.         case IMAGE_TYPE:
  460.             usprintf(control,"TYPE I\r\n");
  461.             break;
  462.         case LOGICAL_TYPE:
  463.             usprintf(control,"TYPE L %d\r\n",ftp->logbsize);
  464.             break;
  465.         }
  466.         ftp->typesent = ftp->type;
  467.         resp = getresp(control,200);
  468.         if(resp == -1 || resp > 299){
  469.             return 1;
  470.         }
  471.     }
  472.     if(localname == NULLCHAR){
  473.         fp = stdout;
  474.     } else if((fp = fopen(localname,mode)) == NULLFILE){
  475.         printf("Can't write %s: %s\n",localname,sys_errlist[errno]);
  476.         return 1;
  477.     }
  478.     /* Open the data connection */
  479.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  480.     listen(ftp->data,0);    /* Accept only one connection */
  481.     ftp->state = RECEIVING_STATE;
  482.  
  483.     /* Send the PORT message and wait for ack */
  484.     i = SOCKSIZE;
  485.     getsockname(ftp->data,(char *)&lsocket,&i);
  486.     sendport(control,&lsocket);
  487.     resp = getresp(control,200);
  488.     if(resp == -1 || resp > 299){
  489.         /* Error, quit */
  490.         if(fp != stdout)
  491.             fclose(fp);
  492.         close_s(ftp->data);
  493.         ftp->data = -1;
  494.         ftp->state = COMMAND_STATE;
  495.         return 1;
  496.     }
  497.     /* Generate the command to start the transfer and wait for ack */
  498.     if(remotename != NULLCHAR)
  499.         usprintf(control,"%s %s\r\n",command,remotename);
  500.     else
  501.         usprintf(control,"%s\r\n",command);
  502.     /* Get the intermediate "150" response */
  503.     resp = getresp(control,100);
  504.     if(resp == -1 || resp >= 400){
  505.         /* Error, quit */
  506.         if(fp != stdout)
  507.             fclose(fp);
  508.         close_s(ftp->data);
  509.         ftp->data = -1;
  510.         ftp->state = COMMAND_STATE;
  511.         return 1;
  512.     }
  513.     /* Wait for the server to open the data connection */
  514.     cnt = 0;
  515.     ftp->data = accept(ftp->data,NULLCHAR,&cnt);
  516.     startclk = Clock;
  517.  
  518.     total = recvfile(fp,ftp->data,ftp->type);
  519.     /* Immediately close the data connection; some servers (e.g., TOPS-10)
  520.      * wait for the data connection to close completely before returning
  521.      * the completion message on the control channel
  522.      */
  523.     close_s(ftp->data);
  524.     ftp->data = -1;
  525.  
  526. #ifdef    CPM
  527.     if(ftp->type == ASCII_TYPE)
  528.         fputc(CTLZ,fp);
  529. #endif
  530.     if(fp != stdout)
  531.         fclose(fp);
  532.     startclk = Clock - startclk;
  533.     if(startclk != 0)
  534.         rate = total/startclk;
  535.     else
  536.         rate = 0;
  537.     if(total != -1)
  538.         printf("Get complete: %lu bytes in %lu sec (%lu/sec)\n",
  539.          total,(startclk*MSPTICK)/1000,(rate*1000)/MSPTICK);
  540.     else
  541.         printf("Error or abort during data transfer\n");
  542.     getresp(control,200);
  543.  
  544.     ftp->state = COMMAND_STATE;
  545.     return 0;
  546. }
  547. /* Send a file. Syntax: put <local name> [<remote name>] */
  548. static int
  549. doput(argc,argv,p)
  550. int argc;
  551. char *argv[];
  552. void *p;
  553. {
  554.     char *remotename,*localname,*mode;
  555.     register struct ftpcli *ftp;
  556.     int i,resp,control;
  557.     unsigned long total;
  558.     FILE *fp;
  559.     struct sockaddr_in lsocket;
  560.     int32 startclk,rate;
  561.     struct session *sp;
  562.  
  563.     sp = (struct session *)p;
  564.     if(sp == NULLSESSION)
  565.         return -1;
  566.     ftp = sp->cb.ftp;
  567.     control = ftp->control;
  568.  
  569.     if(ftp == NULLFTP){
  570.         printf(Notsess);
  571.         return 1;
  572.     }
  573.     localname = argv[1];
  574.     if(argc < 3)
  575.         remotename = localname;
  576.     else
  577.         remotename = argv[2];
  578.  
  579.     if(ftp->type == IMAGE_TYPE)
  580.         mode = READ_BINARY;
  581.     else
  582.         mode = READ_TEXT;
  583.  
  584.     /* Send TYPE message, if necessary */
  585.     if(ftp->typesent != ftp->type){
  586.         switch(ftp->type){
  587.         case ASCII_TYPE:
  588.             usprintf(control,"TYPE A\r\n");
  589.             break;
  590.         case IMAGE_TYPE:
  591.             usprintf(control,"TYPE I\r\n");
  592.             break;
  593.         case LOGICAL_TYPE:
  594.             usprintf(control,"TYPE L %d\r\n",ftp->logbsize);
  595.             break;
  596.         }
  597.         ftp->typesent = ftp->type;
  598.         resp = getresp(control,200);
  599.         if(resp == -1 || resp > 299){
  600.             return 1;
  601.         }
  602.     }
  603.     if((fp = fopen(localname,mode)) == NULLFILE){
  604.         printf("Can't read %s: %s\n",localname,sys_errlist[errno]);
  605.         return 1;
  606.     }
  607.     /* Open the data connection */
  608.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  609.     listen(ftp->data,0);
  610.  
  611.     ftp->state = SENDING_STATE;
  612.  
  613.     /* Send the PORT message and wait for ack */
  614.     i = SOCKSIZE;
  615.     getsockname(ftp->data,(char *)&lsocket,&i);
  616.     sendport(control,&lsocket);
  617.     resp = getresp(control,200);
  618.     if(resp == -1 || resp > 299){
  619.         /* Error, quit */
  620.         fclose(fp);
  621.         close_s(ftp->data);
  622.         ftp->data = -1;
  623.         ftp->state = COMMAND_STATE;
  624.         return 1;
  625.     }
  626.     /* Generate the command to start the transfer and wait for ack */
  627.     usprintf(control,"STOR %s\r\n",remotename);
  628.     resp = getresp(control,100);
  629.     if(resp == -1 || resp >= 400){
  630.         /* Error, quit */
  631.         fclose(fp);
  632.         close_s(ftp->data);
  633.         ftp->data = -1;
  634.         ftp->state = COMMAND_STATE;
  635.         return 1;
  636.     }
  637.     /* Wait for the data connection to open. Otherwise the first
  638.      * block of data would go out with the SYN, and this may confuse
  639.      * some other TCPs
  640.      */
  641.     accept(ftp->data,NULLCHAR,(int *)NULL);
  642.  
  643.     startclk = Clock;
  644.  
  645.     total = sendfile(fp,ftp->data,ftp->type);
  646.     close_s(ftp->data);
  647.     ftp->data = -1;
  648.     fclose(fp);
  649.  
  650.     startclk = Clock - startclk;
  651.     if(startclk != 0)
  652.         rate = total/startclk;
  653.     else
  654.         rate = 0;
  655.     if(total != -1)
  656.         printf("Put complete: %lu bytes in %lu sec (%lu/sec)\n",
  657.          total,(startclk*MSPTICK)/1000,(rate*1000)/MSPTICK);
  658.     else
  659.         printf("Error or abort during data transfer\n");
  660.  
  661.     getresp(control,200);
  662.     ftp->state = COMMAND_STATE;
  663.     return 1;
  664. }
  665. /* Abort a GET or PUT operation in progress. Note: this will leave
  666.  * the partial file on the local or remote system
  667.  */
  668. int
  669. doabort(argc,argv,p)
  670. int argc;
  671. char *argv[];
  672. void *p;
  673. {
  674.     register struct ftpcli *ftp;
  675.     struct session *sp;
  676.  
  677.     sp = (struct session *)p;
  678.     if(sp == NULLSESSION)
  679.         return -1;
  680.  
  681.     /* Default is the current session, but it can be overridden with
  682.      * an argument.
  683.      */
  684.     if(argc > 1)
  685.         sp = sessptr(argv[1]);
  686.  
  687.     if(sp == NULLSESSION || sp->type != FTP){
  688.         printf("Not an active FTP session\n");
  689.         return 1;
  690.     }
  691.     ftp = sp->cb.ftp;
  692.  
  693.     switch(ftp->state){
  694.     case COMMAND_STATE:
  695.         printf("No active transfer\n");
  696.         return 1;
  697.     case SENDING_STATE:
  698.         /* Send a premature EOF.
  699.          * Unfortunately we can't just reset the connection
  700.          * since the remote side might end up waiting forever
  701.          * for us to send something.
  702.          */
  703.         shutdown(ftp->data,1);
  704.         break;
  705.     case RECEIVING_STATE:
  706.         /* Just blow away the receive socket */
  707.         shutdown(ftp->data,2);
  708.         break;
  709.     }
  710.     return 0;
  711. }
  712. /* send PORT message */
  713. static void
  714. sendport(s,socket)
  715. int s;
  716. struct sockaddr_in *socket;
  717. {
  718.     struct mbuf *bp;
  719.  
  720.     /* Compose and send PORT a,a,a,a,p,p message */
  721.     if((bp = alloc_mbuf(35)) == NULLBUF){    /* 5 more than worst case */
  722.         printf(Nospace);
  723.         return;
  724.     }
  725.     /* I know, this looks gross, but it works! */
  726.     sprintf(bp->data,"PORT %u,%u,%u,%u,%u,%u\r\n",
  727.         hibyte(hiword(socket->sin_addr.s_addr)),
  728.         lobyte(hiword(socket->sin_addr.s_addr)),
  729.         hibyte(loword(socket->sin_addr.s_addr)),
  730.         lobyte(loword(socket->sin_addr.s_addr)),
  731.         hibyte(socket->sin_port),
  732.         lobyte(socket->sin_port));
  733.     bp->cnt = strlen(bp->data);
  734.     send_mbuf(s,bp,0,NULLCHAR,0);
  735. }
  736.  
  737. /* Wait for, read and display response from FTP server. Return the result code.
  738.  */
  739. int
  740. getresp(s,mincode)
  741. int s;
  742. int mincode;    /* Keep reading until at least this code comes back */
  743. {
  744.     register char *line;
  745.     int rval;
  746.  
  747.     line = malloc(256);
  748.     for(;;){
  749.         /* Get line */
  750.         if(recvline(s,line,256) == -1){
  751.             rval = -1;
  752.             break;
  753.         }
  754.         rip(line);        /* Remove cr/lf */
  755.         printf("%s\n",line);    /* Display to user */
  756.  
  757.         /* Messages with dashes are continued */
  758.         if(line[3] != '-' && (rval = atoi(line)) >= mincode)
  759.             break;
  760.     }
  761.     free(line);
  762.     return rval;
  763. }
  764.  
  765. /* Issue a prompt and read a line from the user */
  766. struct mbuf *
  767. getline(sp,prompt)
  768. struct session *sp;
  769. char *prompt;
  770. {
  771.     /* If there's something already there, just grab it */
  772.     if(sp->input != NULLBUF)
  773.         return dequeue(&sp->input);
  774.  
  775.     /* Wait until we're the current session, issue prompt, and get line */
  776.     while(Current != sp || Mode != CONV_MODE)
  777.         pwait(sp);
  778.     printf("%s",prompt);
  779.     while(sp->input == NULLBUF)
  780.         pwait(&sp->input);
  781.     return dequeue(&sp->input);
  782. }
  783.